import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:file_saver/file_saver.dart';
import 'package:file_selector/file_selector.dart';
import 'package:filelinker/alert.dart';
import 'package:filelinker/file_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:mime/mime.dart';
import 'package:path_provider/path_provider.dart';
import 'package:saver_gallery/saver_gallery.dart';
import 'package:shared_preferences/shared_preferences.dart';
// ignore: implementation_imports
import 'package:file_saver/src/utils/helpers.dart';

class NetService {
  static NetService shared = NetService();

  final List<RecvFile> recvFiles = [];

  VoidCallback? onGetFileNames;
  VoidCallback? onRecvFile;
  Function(String text)? onGetText;

  BuildContext? context;

  bool _permissionGranted = false;
  String downloadFolder = "";

  SharedPreferences? _prefs;

  Future preload() async {
    await _initPrefs();
    downloadFolder = _prefs?.getString("downloadFolder") ?? "";
    if (downloadFolder.isEmpty) {
      downloadFolder = await Helpers.getDirectory().then((v) => v ?? "");
    }
    _prefs?.setString("downloadFolder", downloadFolder);
    debugPrint("download folder: $downloadFolder");
    _permissionGranted = _prefs?.getBool("permissionGranted") ?? false;
    debugPrint('permissionGranted: $_permissionGranted');
  }

  Future preloadPermission() async {
    await _initPrefs();
    _permissionGranted = _prefs?.getBool("permissionGranted") ?? false;
    debugPrint('permissionGranted: $_permissionGranted');
    if (_permissionGranted) await preload();
  }

  Future<void> _initPrefs() async {
    _prefs ??= await SharedPreferences.getInstance();
  }

  bool get permissionGranted => _permissionGranted;

  set permissionGranted(bool value) {
    _permissionGranted = value;
    _prefs?.setBool("permissionGranted", _permissionGranted);
  }

  Future updateDownloadFolder(String path) async {
    downloadFolder = path;
    _prefs?.setString("downloadFolder", downloadFolder);
    debugPrint("download folder: $downloadFolder");
  }

  void start(int port) async {
    var server = await HttpServer.bind("0.0.0.0", port);
    await server.forEach((request) {
      if (request.method == 'POST') {
        if (request.uri.path == '/upload') {
          _handleUpload(request);
        } else if (request.uri.path == '/files') {
          _handleFiles(request);
        } else if (request.uri.path == '/text') {
          _handleText(request);
        }
      } else {
        request.response.statusCode = 200;
        request.response.write("OK");
        request.response.close();
      }
    });
    debugPrint('HTTP server listening on port $port');
  }

  String _response(Map<String, dynamic> data, String message, {int code = 200}) {
    return json.encode({
      "message": message,
      "data": data,
      "code": code,
    });
  }

  Future<void> _handleUpload(HttpRequest request) async {
    var transformer = MimeMultipartTransformer(request.headers.contentType?.parameters["boundary"] ?? "");
    final parts = await transformer.bind(request).toList();
    bool isResponsed = false;

    void saveSuccess(String filename) {
      recvFiles.firstWhere((file) => file.name == filename).isRecvied = true;
      if (onRecvFile != null) onRecvFile!();
      // 返回响应
      request.response.write(_response({}, '文件上传成功', code: 200));
      request.response.close();
      isResponsed = true;
    }

    void saveFailure() {
      request.response.write(_response({}, '文件上传失败', code: 406));
      request.response.close();
    }

    for (var part in parts) {
      if (part.headers['content-disposition']?.contains('filename') == false) {
        saveFailure();
        continue;
      }
      final file = part.headers['content-disposition']
          ?.split(';')
          .firstWhere(
            (element) => element.trim().startsWith('filename='),
          )
          .split('=')[1]
          .trim()
          .replaceAll('"', '');

      List<String> infos = file?.split("#") ?? [];
      final filename = infos.isNotEmpty ? infos[0] : null;
      final length = int.tryParse(infos.length > 1 ? infos[1] : '0');

      if (filename == null || length == null) {
        saveFailure();
        continue;
      }
      debugPrint('文件名: $filename, 大小: $length');

      final content = await part.fold<List<int>>(<int>[], (b, d) {
        b.addAll(d);
        final reciveSize = b.length;
        final progress = reciveSize / length;
        recvFiles.firstWhere((file) => file.name == filename).progress = progress;
        if (progress % 0.1 == 0 && onRecvFile != null) onRecvFile!();
        return b;
      });

      debugPrint('完成接收：$filename，准备保存');

      // 保存文件
      if (Platform.isIOS) {
        if (isVideo(filename)) {
          final path = await getTemporaryDirectory();
          final file = File('${path.path}/$filename');
          file.writeAsBytesSync(content);
          final result = await SaverGallery.saveFile(
            filePath: file.path,
            fileName: filename,
            skipIfExists: false,
          );
          debugPrint('movie result: $result');
        } else if (isImage(filename)) {
          final result = await SaverGallery.saveImage(
            Uint8List.fromList(content),
            quality: 100,
            fileName: filename,
            skipIfExists: false,
          );
          debugPrint('image result: $result');
        }
        // 返回响应
        saveSuccess(filename);
      } else {
        try {
          final result = await FileSaver.instance.saveFile(
            bytes: Uint8List.fromList(content),
            filePath: downloadFolder,
            name: filename,
          );
          debugPrint('result: $result');
          // 返回响应
          saveSuccess(filename);
        } catch (e) {
          debugPrint("保存失败：$e");
          EasyLoading.showError("保存文件$filename失败");
        }
      }
      if (!isResponsed) {
        saveFailure();
      }
    }
  }

  void _handleFiles(HttpRequest request) async {
    final data = json.decode(await utf8.decoder.bind(request).join());
    final List fileNames = data['files'] as List;
    final name = data['name'] as String;

    bool accepted = await Alert(context!).showWarning(
      '上传文件',
      '$name 想要给你发送文件，是否同意接受？',
    );
    if (!accepted) {
      request.response.write(_response({}, '拒绝接收文件', code: 406));
      request.response.close();
      return;
    }

    if (fileNames.isNotEmpty) {
      for (var name in fileNames) {
        final file = RecvFile(name);
        if (recvFiles.any((e) => e.name == name)) {
          continue;
        }
        recvFiles.add(file);
      }
    }

    // 回复响应
    debugPrint("recvFiles: $recvFiles");
    if (onGetFileNames != null) {
      onGetFileNames!();
    }

    // 返回响应
    request.response.write(_response({}, '文件接收成功', code: 200));
    request.response.close();
  }

  void _handleText(HttpRequest request) async {
    final data = json.decode(await utf8.decoder.bind(request).join());
    final name = data['name'] as String;

    bool accepted = await Alert(context!).showWarning(
      '接收文本',
      '$name 想要给你发送文本，是否同意接受？',
    );
    if (!accepted) {
      request.response.write(_response({}, '拒绝接收文本', code: 406));
      request.response.close();
      return;
    }
    if (onGetText != null) {
      onGetText!(data['text']);
    }
    // 返回响应
    request.response.write(_response({}, '文本接收成功', code: 200));
    request.response.close();
  }

  Future<bool> uploadFile(XFile file, String host, int? port) async {
    // 创建 multipart 请求
    final request = http.MultipartRequest('POST', Uri.parse('http://$host:$port/upload'));

    // 添加文件到请求
    List<int> bytes = await file.readAsBytes();
    final multipartFile = http.MultipartFile.fromBytes(
      'file',
      bytes,
      filename: "${file.name}#${bytes.length}",
      contentType: MediaType(
        'application',
        'octet-stream',
      ),
    );
    request.files.add(multipartFile);

    try {
      // 发送请求
      final response = await request.send();
      final body = await response.stream.transform(utf8.decoder).join();
      final data = json.decode(body);
      debugPrint("上传文件响应：$data");
      bool accepted = data['code'] == 200;

      // 检查响应状态码
      if (accepted) {
        debugPrint('文件已成功上传！');
      } else {
        debugPrint('上传文件失败，状态码：${data['code']}');
      }
      return accepted;
    } catch (e) {
      debugPrint("上传文件异常：$e");
      return false;
    }
  }

  Future<NetServiceState> askFiles(List<XFile> files, String host, int? port, String name) async {
    List<String> names = files.map((e) => e.name).toList();
    final url = Uri.parse('http://$host:$port/files');
    final body = json.encode({"files": names, "name": name});

    debugPrint('Url：$url\nSend files：$body');
    NetServiceState state = NetServiceState.none;

    try {
      final response = await http.post(url, headers: {'Content-Type': 'application/json'}, body: body).timeout(const Duration(seconds: 30));
      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        debugPrint('Send files result：$data');
        state = data['code'] == 200 ? NetServiceState.accepted : NetServiceState.rejected;
      } else {
        debugPrint('Send files failed：${response.statusCode}');
        state = NetServiceState.rejected;
      }
    } catch (e) {
      debugPrint("Send files failed: $e");
      state = NetServiceState.connectFailed;
    }
    return state;
  }

  Future<bool> sendText(String host, int? port, String text, String name) async {
    final url = Uri.parse('http://$host:$port/text');
    final body = json.encode({"text": text, "name": name});

    debugPrint('Url：$url\nSend text：$body');
    try {
      final response = await http.post(url, headers: {'Content-Type': 'application/json'}, body: body).timeout(const Duration(seconds: 30));
      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        debugPrint('Send text result：$data');
        return data['code'] == 200;
      } else {
        debugPrint('Send text failed：${response.statusCode}');
        return false;
      }
    } catch (e) {
      debugPrint("Send text failed: $e");
      return false;
    }
  }
}

enum NetServiceState {
  none,
  accepted,
  rejected,
  connectFailed,
}
